﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TrafficApp
{
    public partial class TrafficLightSimulator : Form
    {
        private App Applic;// 18 nr of components
        private Rectangle dragBoxFromMouseDown;
        private int lastMouseDownX, lastMouseDownY;
        private int lastMouseClickX, lastMouseClickY; // will be needed for streets
        private Point screenOffset;
        private Point hoverLoc = new Point(0, 0);
        private Point selectLoc = new Point(0, 0);
        private bool moving = false;
        private bool selected = false;
        //private string filePath = "";

        public TrafficLightSimulator()
        {

            InitializeComponent();
            Applic = new App(18, this.pbxMain);
            Applic.AddCrossing(new Vector(), "Cross1"); // ? For demonstration purposes
            lblStatus1.Text = "";
            this.MouseMove += new MouseEventHandler(this.MainForm_MouseMove);
            pbxSide.MouseDown += new MouseEventHandler(pbxSide_MouseDown);
            pbxSide.MouseUp += new MouseEventHandler(pbxSide_MouseUp);
            pbxSide.MouseMove += new MouseEventHandler(pbxSide_MouseMove);
            pbxSide.GiveFeedback += new System.Windows.Forms.GiveFeedbackEventHandler(this.pbxSide_GiveFeedback);
            pbxSide.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(pbxSide_QueryContinueDrag);
            pbxSide.MouseDoubleClick +=new MouseEventHandler(pbxSide_MouseDoubleClick);

            pbxMain.AllowDrop = true;
            pbxMain.MouseClick +=new MouseEventHandler(pbxMain_MouseClick);
            pbxMain.MouseMove += new MouseEventHandler(pbxMain_MouseMove);
            pbxMain.MouseDown += new MouseEventHandler(pbxMain_MouseDown);
            pbxMain.DragOver += new DragEventHandler(pbxMain_DragOver);
            pbxMain.DragDrop += new DragEventHandler(pbxMain_DragDrop);
            pbxMain.DragEnter += new System.Windows.Forms.DragEventHandler(pbxMain_DragEnter);
            pbxMain.DragLeave += new System.EventHandler(pbxMain_DragLeave);
            pbxMain.MouseLeave += new System.EventHandler(pbxMain_MouseLeave);
            pbxMain.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(pbxMain_QueryContinueDrag);
            this.pbxMain.Paint += new System.Windows.Forms.PaintEventHandler(Applic.Draw);

        }

        /*	`Drag and drop implementation 
        --------------------------------------------------------------*/
         #region DragAndDrop
        private void MainForm_MouseMove(object sender, MouseEventArgs e) // needed for D&D
        {
        }

        private void pbxSide_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            dragBoxFromMouseDown = Rectangle.Empty;
        }
        private void pbxSide_MouseDown(object sender, MouseEventArgs e)
        {
            moving = false;
            lastMouseDownX = e.X;
            lastMouseDownY = e.Y;
        }

        /// <summary>
        ///  changes the cursor to Hand when hovering in specified areas in side toolbar (pbxSide)
        /// </summary>
        private void pbxSide_MouseMove(object sender, MouseEventArgs e)
        {
            string cType = "";
            Rectangle compRect = new Rectangle(); // side component rectangle for hover
            pbxSide.Cursor = Cursors.Hand;
            if ((e.X >= 15 && e.Y >= 15) && (e.X <= 115 && e.Y <= 115))
            {
                cType = "Cross 1";
                compRect = new Rectangle(14, 14, 101, 101);
                lblStatus2.Text = "Drag and Drop " + cType;
            }
            else if((e.X >= 15 && e.Y >= 145) && (e.X <= 115 && e.Y <= 245))
            {
                cType = "Cross 2";
                compRect = new Rectangle(14, 144, 101, 101);
                lblStatus2.Text = "Drag and Drop " + cType;
            }
            else
            {
                pbxSide.Cursor = Cursors.Default;
                lblStatus2.Text = "";
                compRect = new Rectangle(-1,-1,-1,-1);
            }
            hoverSide(compRect);
            
            if ((e.Button & MouseButtons.Left) == MouseButtons.Left && cType != "")
            {

                try
                {
                    //MyNormalCursor = new Cursor("3dwarro.cur");
                    //MyNoDropCursor = new Cursor("3dwno.cur");
                }
                catch
                {
                    // An error occurred while attempting to load the cursors, so use
                    // standard cursors.
                    //UseCustomCursorsCheck.Checked = false;
                }
                finally
                {
                    screenOffset = SystemInformation.WorkingArea.Location;
                    DragDropEffects dropEffect = pbxSide.DoDragDrop(pbxSide.Capture, DragDropEffects.All | DragDropEffects.Link);
                    if (dropEffect == DragDropEffects.Move) //?
                    {
                    }
                }
            }
        }
        /// <summary>
        /// Gives user feedback visualy on hovering specific region
        /// </summary>
        private void pbxSide_GiveFeedback(object sender, System.Windows.Forms.GiveFeedbackEventArgs e)
        {
        }

        private void pbxMain_MouseDown(object sender, MouseEventArgs e)
        {
            // Remember the point where the mouse down occurred. The DragSize indicates
            // the size that the mouse can move before a drag event should be started.                
            Size dragSize = new Size(30, 30);

            // Create a rectangle using the DragSize, with the mouse position being
            // at the center of the rectangle.
            dragBoxFromMouseDown = new Rectangle(new Point(e.X - dragSize.Width / 2,
                                                           e.Y - dragSize.Height / 2), dragSize);
            moving = true;
            lastMouseDownX = e.X;
            lastMouseDownY = e.Y;

        }

        /// <summary>
        /// Check and informs for any status (ex. Type or cursor positions) 
        /// while moving the mouse in the main area (pbxMain)
        /// </summary>
        private void pbxMain_MouseMove(object sender, MouseEventArgs e)
        {
            if (App.MainTimer.Enabled == true) // no hover check while simulating
                return;
            // TODO  draw street connections if not atomatically
            //if (selected)
            //{
            //    pbxMain.Refresh();
            //    Graphics gr = pbxMain.CreateGraphics();
            //    gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            //}
            hoverLoc = new Point(e.X, e.Y);
            Applic.hoverCell(hoverLoc);
            Vector loc = new Vector(e.X, e.Y);

            if (Applic.getType(loc) != "")
            {
                pbxMain.Cursor = Cursors.Hand;
                lblStatus1.Text = "Component of type " + Applic.getType(loc);
                //Applic.hoverCell(new Vector(e.X, e.Y), pbxMain);
            }
            else
            {
                pbxMain.Cursor = Cursors.Default;
                lblStatus1.Text = "";
            }
            lblStatus2.Text = e.X + "," + e.Y;


            // Handling the cursor feedback
            if ((e.Button & MouseButtons.Left) == MouseButtons.Left &&
                dragBoxFromMouseDown != Rectangle.Empty && !dragBoxFromMouseDown.Contains(e.X, e.Y) && Applic.isComponent(new Vector(e.X, e.Y)))
            {
                try
                {
                    //MyNormalCursor = new Cursor("3dwarro.cur");
                    //MyNoDropCursor = new Cursor("3dwno.cur");
                }
                catch
                {
                    // An error occurred while attempting to load the cursors, so use
                    // standard cursors.
                    //UseCustomCursorsCheck.Checked = false;
                }
                finally
                {
                    screenOffset = SystemInformation.WorkingArea.Location;
                    DragDropEffects dropEffect = pbxMain.DoDragDrop(pbxMain.Capture, DragDropEffects.All | DragDropEffects.Link);
                    if (dropEffect == DragDropEffects.Move)
                    {
                        // That's the moment draggin is happening 
                        //MessageBox.Show(dropEffect.ToString());
                    }
                }
            }
            pbxMainRefresh();
        }

        private void pbxMain_MouseLeave(object sender, EventArgs e)
        {
            lblStatus1.Text = "";
            lblStatus2.Text = "";
            lblActions.Text = "";
            clearHover();
        }

        private void pbxMain_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
        {
            if (App.MainTimer.Enabled == true)
                return;

            clearHover();
            clearSelection();

            int x, y;
            Point lastCoords = new Point(lastMouseDownX, lastMouseDownY);
            lastCoords = pbxMain.PointToScreen(lastCoords);
            Point screenCoords = Cursor.Position;

            Point controlRelatedCoords = this.pbxMain.PointToClient(screenCoords);
            x = controlRelatedCoords.X;
            y = controlRelatedCoords.Y;
                Vector currCoords = new Vector(lastMouseDownX, lastMouseDownY),
                       newCoords = new Vector(controlRelatedCoords.X, controlRelatedCoords.Y);
            if (moving)
            {
                e.Effect = DragDropEffects.Move;
                lblStatus2.Text = "Move Component";

                if (Applic.moveComponent(currCoords, newCoords))
                {
                    lastMouseDownX = x;
                    lastMouseDownY = y;
                }
                else
                {
                    lblActions.Text = "Cannot move components while simulating";
                }
            }
            else
            {
                if (!Applic.isComponent(newCoords))
                {
                    e.Effect = DragDropEffects.Move;
                    lblStatus2.Text = "Drop";
                }
                else
                {
                    e.Effect = DragDropEffects.None;
                    lblStatus2.Text = "Cannot drop here";
                }
            }
            pbxMainRefresh();
        }
        private void pbxMain_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
        {
            if (App.MainTimer.Enabled == true)
                return;

            int x, y; // ?
            Point screenCoords = Cursor.Position;
            Point controlRelatedCoords = this.pbxMain.PointToClient(screenCoords);
            x = controlRelatedCoords.X; // ?
            y = controlRelatedCoords.Y; // ?

            // Perform drag-and-drop, depending upon the effect.
            if (e.Effect == DragDropEffects.Copy || e.Effect == DragDropEffects.Move)
            {
                if (App.MainTimer.Enabled == true)
                    return;
                string type;
                if (!moving)
                {
                    if ((lastMouseDownX >= 15 && lastMouseDownY >= 15) && (lastMouseDownX <= 115 && lastMouseDownY <= 115))
                        type = "Cross1";
                    else if ((lastMouseDownX >= 15 && lastMouseDownY >= 145) && (lastMouseDownX <= 115 && lastMouseDownY <= 245))
                        type = "Cross2";
                    else
                        type = "";
                    if (type != "")
                    {
                        Vector Loc = new Vector(controlRelatedCoords);
                        if (Applic.AddCrossing(Loc, type))
                            lblActions.Text = type + " added.";
                        else
                            lblActions.Text = "Simulation on or maximum number of components reached!";
                    }
                    pbxMainRefresh();
                }
                else
                {
                    moving = false;
                }
            }
            //selected = false;
            // TODO ? selected never true
            //if (selected)
            //    lblStatus1.Text = "Selected";
            //else
            //    lblStatus1.Text = "Not Selected";
        }

        private void pbxSide_QueryContinueDrag(object sender, System.Windows.Forms.QueryContinueDragEventArgs e)
        {
            // Cancel the drag if the mouse moves off the form.
            PictureBox pb = sender as PictureBox;

            if (pb != null)
            {

                Form f = pb.FindForm();

                // Cancel the drag if the mouse moves off the form. The screenOffset
                // takes into account any desktop bands that may be at the top or left
                // side of the screen.
                if (((Control.MousePosition.X - screenOffset.X) < f.DesktopBounds.Left) ||
                    ((Control.MousePosition.X - screenOffset.X) > f.DesktopBounds.Right) ||
                    ((Control.MousePosition.Y - screenOffset.Y) < f.DesktopBounds.Top) ||
                    ((Control.MousePosition.Y - screenOffset.Y) > f.DesktopBounds.Bottom))
                {
                    lblStatus2.Text = "Cannot drop outside";
                    e.Action = DragAction.Cancel;
                }
            }
        }
        private void pbxMain_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
        {
            //lblTempDevStatus2.Text = e.X + ", " + e.Y;
        }
        private void pbxMain_DragLeave(object sender, System.EventArgs e)
        {
            //lblStatus1.Text = "";
        }
        private void pbxMain_QueryContinueDrag(object sender, System.Windows.Forms.QueryContinueDragEventArgs e)
        {
            if (App.MainTimer.Enabled == true)
                return;

            // Cancel the drag if the mouse moves off the form.
            PictureBox pb = sender as PictureBox;
            if (pb != null)
            {

                Form f = pb.FindForm();

                // Cancel the drag if the mouse moves off the form. The screenOffset
                // takes into account any desktop bands that may be at the top or left
                // side of the screen.
                if (((Control.MousePosition.X - screenOffset.X) < f.DesktopBounds.Left) ||
                    ((Control.MousePosition.X - screenOffset.X) > f.DesktopBounds.Right) ||
                    ((Control.MousePosition.Y - screenOffset.Y) < f.DesktopBounds.Top) ||
                    ((Control.MousePosition.Y - screenOffset.Y) > f.DesktopBounds.Bottom))
                {

                    e.Action = DragAction.Cancel;
                }
            }
        }
       private void pbxMainRefresh()
        {
            pbxMain.Refresh();
            Applic.Draw(pbxMain);
            //if (selected)
            //    lblStatus1.Text = "Selected";
            //else
            //    lblStatus1.Text = "Not Selected";
        }

        private void MainForm_Move(object sender, EventArgs e)
        {
            pbxMainRefresh();
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            pbxMainRefresh();
        }

        private void MainForm_SizeChanged(object sender, EventArgs e)
        {
            pbxMainRefresh();
        }

        // TODO double click of a Component
        private void pbxMain_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            /* TODO selection of crossings in double click
            if (Applic.isComponent(e.X, e.Y))
            {
                if (Applic.getCrossingType(e.X, e.Y) != "")
                {
                    Applic.removeConnex(e.X, e.Y);
                    pbxMainRefresh();
                    selected = false;
                }
            }
            else
            {
                selected = false;
            }
            if (selected)
                lblStatus1.Text = "Selected";
            else
                lblStatus1.Text = "Not Selected";
            */
        }

        // TODO select a Component
        private void pbxMain_MouseClick(object sender, MouseEventArgs e)
        {
            if (App.MainTimer.Enabled == true)
                return;

            if (Applic.isComponent(new Vector(e.X, e.Y)))
            {
                selectLoc = new Point(e.X, e.Y);
                Applic.selectCell(selectLoc);
            }
            else
            {
                clearSelection();
            }
            lblStatus1.Text = "";
            lblStatus2.Text = "";
            lblActions.Text = "";
            /* TODO
            int result = Applic.getCrossingType(e.X, e.Y);
            if (result != -1)
            {
                if (selected)
                {
                    if (result == 1)
                    {
                        if (Applic.addConnex(lastMouseClickX, lastMouseClickY, e.X, e.Y))
                        {
                        }
                    }
                    else
                    {
                        if (Applic.addConnex(e.X, e.Y, lastMouseClickX, lastMouseClickY))
                        {
                        }
                    }
                    selected = false;

                }
                else
                {
                    selected = true;
                }
                lastMouseClickX = e.X;
                lastMouseClickY = e.Y;
            }
            else
            {
                selected = false;
            }
            if (selected)
                lblStatus1.Text = "Selected";
            else
                lblStatus1.Text = "Not Selected";
        */
            pbxMainRefresh();
        }
        #endregion DragAndDrop

        #region Double click in the sidebar Components
        /// <summary>
        /// Add component by double click
        /// </summary>
        private void pbxSide_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if ((e.X >= 15 && e.Y >= 15) && (e.X <= 115 && e.Y <= 115) ||
                (e.X >= 15 && e.Y >= 145) && (e.X <= 115 && e.Y <= 245))
            {
                if (e.Y < 115)
                {
                    AddCross1(sender, e);
                }
                else if (e.Y < 245)
                {
                    AddCross2(sender, e);
                }
            }
        }

        #endregion

        private void newWorksheetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Applic.NewGrid();
        }

        private void loadWorksheetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Applic.LoadGrid();
        }

        private void saveWorkSheetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Applic.SaveGrid();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (true) //TODO: implement change check (boolean)
            {
                DialogResult dr = MessageBox.Show("Do you want to save before you exit?",
                          "Warning", MessageBoxButtons.YesNo);
                switch (dr)
                {
                    case DialogResult.Yes:
                        Applic.SaveGrid();
                        this.Close();
                        break;

                    case DialogResult.No:
                        this.Close();
                        break;
                }
            }
        }

        // Helping methods for clearing hover/selection in the main
        private void clearHover()
        {
            hoverLoc.X = 0;
            Applic.hoverCell(hoverLoc);
        }
        private void clearSelection()
        {
            selectLoc.X = 0;
            Applic.selectCell(selectLoc);
        }

        /// <summary>
        /// Hover the toolbar
        /// </summary>
        private void hoverSide(Rectangle rect)
        {
            Image image = Image.FromFile(@"..\..\Resources\AllComp.png");
            Pen myPen = new Pen(Color.LimeGreen, 2);
            Graphics gfx = pbxSide.CreateGraphics();
            
            if (rect.X != -1)
            {
                gfx.DrawRectangle(myPen, rect);
            }
            else
            {   
                gfx.DrawImage(image, 0, 0, 130, 540);
            }
            
            gfx.Dispose();
        }

        private void deleteCrossingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (Applic.DelCrossing())
                lblActions.Text = "Component deleted!";
            else
                lblActions.Text = "Click on a component to delete! / Cannot delete if Simulation is on";
            clearSelection();
            pbxMainRefresh();
        }

        private void tBtnPlay_Click(object sender, EventArgs e)
        {
            Applic.StartSim();
        }

        private void tBtnPause_Click(object sender, EventArgs e)
        {
            Applic.PauseSim();
        }

        private void tBtnStop_Click(object sender, EventArgs e)
        {
           Applic.StopSim();
        }

        private void AddCross1(object sender, EventArgs e)
        {
            if (Applic.AddCrossing("Cross1"))
            {
                lblActions.Text = "Cross1 added.";
                pbxMainRefresh();
            }
            else
                lblActions.Text = "Simulation on or maximum number of components reached!";

            clearSelection();
        }

        private void AddCross2(object sender, EventArgs e)
        {
            if (Applic.AddCrossing("Cross2"))
            {
                lblActions.Text = "Cross2 added.";
                pbxMainRefresh();
            }
            else
                lblActions.Text = "Simulation on or maximum number of components reached!";

            clearSelection();

        }

        private void tBtnAbout_Click(object sender, EventArgs e)
        {
            Form about = new AboutForm();
            about.Show();
        }
    //TODO Logo Icon
    }
}
